// /////////////////////////////////////////////////////////////////////////////
//
// Name:            BillboardComponent.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Component wrapper of Irrlicht's IBillboardSceneNode.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "BillboardComponent.h"
#include "../../core/GameManager.h"


// BillboardComponent class
// BillboardComponent constructor (default).
BillboardComponent::BillboardComponent(Entity *parent, const dimension2df &size,
                                       const SColor &colorTop, const SColor &colorBottom)
: SceneComponent(parent, true)
{
    if(pParent != NULL)
    {
       // Get pointers to needed sub-systems of the Game Manager.
       ISceneManager *pSceneMgr = GameManager::Instance()->getSceneManager();

       // Create the internal scene node.
       mBillboardSN = pSceneMgr->addBillboardSceneNode(0, size, parent->getAbsolutePosition(),
                                                    parent->getID(), colorTop, colorBottom);
       mSceneNode = mBillboardSN;

       // Set-up internal mechanism for collision detection.
       mTriSelector = pSceneMgr->createTriangleSelectorFromBoundingBox(mBillboardSN);
       mMetaSelector = pSceneMgr->createMetaTriangleSelector();
    }
}

// BillboardComponent constructor (derivatives).
BillboardComponent::BillboardComponent(Entity *parent, bool isDerived)
: SceneComponent(parent, true)
{
}

// BillboardComponent deconstructor.
BillboardComponent::~BillboardComponent()
{
    if(pParent != NULL)
    {
       if(mBillboardSN != NULL)
       {
          mBillboardSN->remove();
          mSceneNode = NULL;
       }
    }
}

// Returns a direct pointer to the IBillboardSceneNode.
IBillboardSceneNode* BillboardComponent::getBillboardSceneNode()
{
    return mBillboardSN;
}

// Gets the color of the top and bottom vertices of the billboard.
void BillboardComponent::getColor(SColor &topColor, SColor &bottomColor) const
{
    mBillboardSN->getColor(topColor, bottomColor);
}

// Returns the size of the billboard.
const dimension2df& BillboardComponent::getSize() const
{
    return mBillboardSN->getSize();
}

// Sets the color of all vertices of the billboard.
void BillboardComponent::setColor(const SColor &overallColor)
{
    mBillboardSN->setColor(overallColor);
}

// Sets the color of the top and bottom vertices of the billboard.
void BillboardComponent::setColor(const SColor &topColor, const SColor &bottomColor)
{
    mBillboardSN->setColor(topColor, bottomColor);
}

// Sets the size of the billboard.
void BillboardComponent::setSize(const dimension2df &size)
{
    mBillboardSN->setSize(size);
}

// Serializes this object.
bool BillboardComponent::onSerialization(SerializedAttributes *attributes)
{
    // Create a root.
    SerializedAttributes *root = new SerializedAttributes();

    // Serialize SceneComponent elements.
    SceneComponent::onSerialization(root);

    // Serialize color.
    SerializedAttributes *color = new SerializedAttributes();

    SColor topColor, bottomColor;
    mBillboardSN->getColor(topColor, bottomColor);

    color->pushColor("top", topColor);
    color->pushColor("bottom", bottomColor);

    root->pushObject("color", color);
    color->drop();

    // Serialize size.
    root->pushDimension2df("size", mBillboardSN->getSize());

    // Add root to the given collection of attributes.
    attributes->pushObject("BillboardComponent", root);
    root->drop();

    // Return
    return true;
}

// Deserializes this object.
bool BillboardComponent::onDeserialization(SerializedAttributes *attributes)
{
    // Retrieve root attribute from the collection.
    SerializedAttribute *rootAttribute = attributes->pullAttribute();

    if(rootAttribute == NULL || rootAttribute->getName() != "BillboardComponent")
      return false;

    SerializedAttributes *root = reinterpret_cast<SerializedAttributes*>(rootAttribute->getObject());
    root->grab();

    rootAttribute->drop(); // We no longer need this attribute.

    // Process all attributes in the root collection.
    for(SerializedAttribute *attribute = root->pullAttribute(); attribute != NULL; attribute = root->pullAttribute())
    {
       // Deserialize attributes
       if(attribute->getName() == "SceneComponent")
       {
           // Rewrap attribute so that it can be deserialized properly.
           SerializedAttributes *wrappedAttribute = new SerializedAttributes();
           wrappedAttribute->pushAttribute(attribute);

           // Deserialize the component.
           SceneComponent::onDeserialization(wrappedAttribute);

           // Clean up.
           wrappedAttribute->drop();
       }

       else if(attribute->getName() == "color")
       {
          // Convert to a collection of attributes.
          SerializedAttributes *color = reinterpret_cast<SerializedAttributes*>(attribute->getObject());

          // Predeclaration of needed variables.
          SColor topColor, bottomColor;

          // Process all attributes in the color collection.
          for(SerializedAttribute *innerAttribute = color->pullAttribute(); innerAttribute != NULL; innerAttribute = color->pullAttribute())
          {
             // Top attribute.
             if(innerAttribute->getName() == "top")
             {
                topColor = innerAttribute->getColor();
                setColor(topColor, bottomColor);
             }

             // Bottom attribute.
             if(innerAttribute->getName() == "bottom")
             {
                bottomColor = innerAttribute->getColor();
                setColor(topColor, bottomColor);
             }
          }
       }

       else if(attribute->getName() == "size")
          setSize(attribute->getDimension2df());

       // We no longer need a reference to the attribute.
       attribute->drop();
    }

    // We no longer need a reference to the root.
    root->drop();

    // We're done.
    return true;
}

// End of File
